/***************************************************************/
/**********   A L L   N E E D E D   V A R I A B L E S  *********/
/***************************************************************/
int fillR=127,fillG=127,fillB=127;                //FOR INTERACTIVE CHANGES IN COLOR
String data[];
String line1[];
int xRes,yRes;
float pM[],uM[],vM[],nM[];
float near,far,top,bottom,left,right;
int r[],g[],b[];
float rx[],ry[],rz[],sx[],sy[],sz[],tx[],ty[],tz[];
String fileName[];
String sffName[];
float objectS[][][][],objectD[][][][];            //OBJECT 2BE S_tored & D_rawn 
int nFile=4,activeFile=0;
int nSff,nMesh[],nV[][],meshXmid,meshYmid,meshZmid;

//TRANSFORMATION MATRIXES
float rotateMatrixX[][];
float rotateMatrixY[][];
float rotateMatrixZ[][];
float scaleMatrix[][];
float transMatrix[][];
float camMatrix[][];
float projMatrix[][];

//Z-BUFFER AND COLOR BUFFER
int zBuf[][];
color cBuf[][];

//LIGHTING VARIABLES
int AMBIENTi=0,DIFFUSEi=1,SPECULARi=2,POSITIONi=3;
float specularN=1;
int Xi=0,Yi=1,Zi=2,Wi=3;
int Ri=0,Gi=1,Bi=2;
float Light[][][];//Light[id][{Type},{Position}][{Ambient,Diffuse,Specular},{X,Y,Z,W}]
float DifComp[];//foreach light source I need a diffuse component to be calculated before the polygon
                //goes for rendering
int ActiveLights[],numOfLights=5,numOfActiveLights=0,selectedLight=0;
boolean[] AMBIENTon = new boolean[numOfLights],DIFFUSEon = new boolean[numOfLights],SPECULARon = new boolean[numOfLights];
boolean showLightSources=true;

//STORAGE VARIABLES TO BE ABLE TO RASTER POLYGONS OF THE OBJECT TO DRAW
float myMesh[][];//point storage
color myColor;
int pCntr;//point counter

//ALL OTHER INTERACTIVITY VARIABLES
int selectedObject=0,selectedTextArea=0;
int textArea[][],meshTextArea[][][];
String warningText = new String("To see light-effects switch to lighting mode.[Click the text below or press '3']");;
int projectionMode[];//Projection=1,Orthogonal=0;
int drawMode=0;//0 simple/1 zBuffer on/2 backface culling/3 triangulate on
boolean numDisplay=false,moveLight=false;
int drawWireFrames=1;//0 no wires, 1 simple wires, 2 antialiased wires
int selectedColor=0;
int time=0;
float timeInc=5;
boolean timeIncrease=false;
/***************************************************************/
/** B A S I C  V E C T O R  &  M A T R I X  F U N C T I O N S **/
/***************************************************************/
void DogaCopyMatrix(float[] from,float[] to,int n){
  int i=0;
  for (i=0;i<n;i++) to[i]=from[i];
  return;
}
void DogaCopyMatrix2(float[][] from,float[][] to,int row,int col){
  int i=0,j=0;
  for (i=0;i<row;i++)
    for(j=0;j<col;j++)
      to[i][j]=from[i][j];
  return;
}
void DogaMatMult(float matA[][],float matB[][],int A,int B,int C){
  float temp[][];
  int i,j,k;
  temp = new float[C][A];
  for (i=0;i<C;i++)
    for(k=0;k<B;k++)
      temp[i][k] = 0;
  for (i=0;i<C;i++)
    for (j=0;j<A;j++)
      for(k=0;k<B;k++)
        temp[i][j] += matA[j][k]*matB[i][k];
  for (i=0;i<C;i++)
    for (j=0;j<B;j++)
        matB[i][j] = temp[i][j];
  return;
}
float DogaDotProduct(float V1[],float V2[]) {return V1[0]*V2[0]+V1[1]*V2[1]+V1[2]*V2[2];}
float[] DogaCrossProduct(float V1[],float V2[]) {
  float m;
  float[] Vn=new float[4];
  Vn[0] = V1[1]*V2[2] - V2[1]*V1[2];
  Vn[1] = V2[0]*V1[2] - V1[0]*V2[2];
  Vn[2] = V1[0]*V2[1] - V2[0]*V1[1];
  Vn[3] = 1;
  m = sqrt(DogaDotProduct(Vn,Vn));
  for (int i=0;i<3;i++)
    Vn[i] = Vn[i]/m;
  return Vn;
}
void DogaMakeUnitVector(float V[]) {
  float w=0;
  w = sqrt(DogaDotProduct(V,V));
  V[0] = V[0]/w;
  V[1] = V[1]/w;
  V[2] = V[2]/w;
}
/***************************************************************/
/****** H W 2  N E E D E D  B A S I C  F U N C T I O N S********/
/***************************************************************/
void DogaRotateFX(float degX,float degY,float degZ) {
  rotateMatrixX = new float[][]{{1,0,0,0},
                  		 {0,cos(degX),-sin(degX),0},
                  		 {0,sin(degX),cos(degX),0},
                  		 {0,0,0,1}
		                };
  rotateMatrixY = new float[][]{{cos(degY),0,sin(degY),0},
                		{0,1,0,0},
                		{-sin(degY),0,cos(degY),0},
                		{0,0,0,1}
               		        };
  rotateMatrixZ = new float[][]{{cos(degZ),-sin(degZ),0,0},
                		{sin(degZ),cos(degZ),0,0},
                		{0,0,1,0},
                		{0,0,0,1}
	    	               };
  return;
}

void DogaScaleFX(float sizeX,float sizeY,float sizeZ) {
  scaleMatrix = new float[][]{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
  scaleMatrix[0][0] = sizeX;
  scaleMatrix[1][1] = sizeY;
  scaleMatrix[2][2] = sizeZ;
  return;
}
void DogaTranslateFX(float X,float Y,float Z) {
  transMatrix = new float[][]{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
  transMatrix[0][3] = X;
  transMatrix[1][3] = Y;
  transMatrix[2][3] = Z;
  return;
}
void DogaCameraFX(float r[],float u[],float v[],float n[]) {
  camMatrix = new float[][]{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
  DogaCopyMatrix(u,camMatrix[0],4);
  DogaCopyMatrix(v,camMatrix[1],4);
  DogaCopyMatrix(n,camMatrix[2],4);
  camMatrix[0][3] = -DogaDotProduct(r,u);
  camMatrix[1][3] = -DogaDotProduct(r,v);
  camMatrix[2][3] = -DogaDotProduct(r,n);
  return;
}
void DogaProjectionFX(int projMode,float Near,float Far,float Top,float Bottom,float Left,float Right) {
  projMatrix = new float[][]{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
  if ((Right==Left)||(Top==Bottom)||(Far==Near)) return;
  if (projMode==0) {//ORTHOGONAL
    projMatrix[0][0] = (float)2/(Right-Left);
    projMatrix[0][3] = -(float)(Right+Left)/(Right-Left);
    projMatrix[1][1] = (float)2/(Top-Bottom);
    projMatrix[1][3] = -(float)(Top+Bottom)/(Top-Bottom);
    projMatrix[2][2] = -(float)2/(Far-Near);
    projMatrix[2][3] = -(float)(Far+Near)/(Far-Near);
    projMatrix[3][3] = 1;
  }
  else if (projMode==1) {//FRUSTUM
    projMatrix[0][0] = (float)2*Near/(Right-Left);
    projMatrix[0][2] = (float)(Right+Left)/(Right-Left);
    projMatrix[1][1] = (float)2*Near/(Top-Bottom);
    projMatrix[1][2] = (float)(Top+Bottom)/(Top-Bottom);
    projMatrix[2][2] = -(float)(Far+Near)/(Far-Near);
    projMatrix[2][3] = -(float)(2*Far*Near)/(Far-Near);
    projMatrix[3][2] = -1;
    projMatrix[3][3] = 0;    
  }
  return;
}
float winX(float x) {
  return (x+1)*((xRes-1)/2);
}
float winY(float y) {
  return yRes-(y+1)*((yRes-1)/2);
}
//FOR ANALYZING THE MESH TO DRAW ACCORDING TO THE DRAWTYPE(SIMPLE,Z-BUFFER,BACKFACECULLING,LIGHTING)
void DogaSetMesh(int pNum,int x,int y,float z,int R,int G,int B,int W) {
  if (pNum==0) {//the first point of the mesh
    myMesh = new float[10][4];
    myColor = color(R,G,B,W);
    meshXmid=0; meshYmid=0; meshZmid=0;
    pCntr=0;
  }
  myMesh[pCntr][0] = x; meshXmid+=x;
  myMesh[pCntr][1] = y; meshYmid+=y;
  myMesh[pCntr][2] = z; meshZmid+=z;
  pCntr++;
}
void ApplyMatrix(int objectID) {
  //FOR CHANGING THE VALUES OF THE OBJECT TO BE DRAWN BY CHANGING THE SOURCE OBJECT POINTS
  int i=0,j=0,k=0;
  i=objectID;
  DogaRotateFX(rx[i],ry[i],rz[i]);
  DogaScaleFX(sx[i],sy[i],sz[i]);
  DogaTranslateFX(tx[i],ty[i],tz[i]);
  for (j=0;j<nMesh[i];j++) {
    DogaCopyMatrix2(objectS[i][j],objectD[i][j],nV[i][j],4);
    DogaMatMult(rotateMatrixX,objectD[i][j],4,4,nV[i][j]);
    DogaMatMult(rotateMatrixY,objectD[i][j],4,4,nV[i][j]);
    DogaMatMult(rotateMatrixZ,objectD[i][j],4,4,nV[i][j]);
    DogaMatMult(scaleMatrix,objectD[i][j],4,4,nV[i][j]);
    DogaMatMult(transMatrix,objectD[i][j],4,4,nV[i][j]);      
    DogaMatMult(camMatrix,objectD[i][j],4,4,nV[i][j]);
    DogaMatMult(projMatrix,objectD[i][j],4,4,nV[i][j]);
    for (k=0;k<nV[i][j];k++) {// now read every point in mesh
      objectD[i][j][k][0] = winX(objectD[i][j][k][0]/objectD[i][j][k][3]);
      objectD[i][j][k][1] = winY(objectD[i][j][k][1]/objectD[i][j][k][3]);
      objectD[i][j][k][2] = 100*(objectD[i][j][k][2]/objectD[i][j][k][3]);
    }//k-nV
  }//j-nMesh
}
/***************************************************************/
/********* STANDART  PROCESSING  FIRST&LOOP FUNCTIONS***********/
/***************************************************************/
void setup() {
 int i=0,j=0;
 Light = new float[numOfLights][4][4];
 DifComp = new float[numOfLights];
 ActiveLights = new int[numOfLights];
 fileName = new String[]{"scene.txt","scene2.txt","scene3.txt","scene4.txt"};
 readInBasicFile();  
 size(xRes,yRes);
 background(0,50,100);
 PFont myFont = createFont("verdana", 12);
 textFont(myFont);
 setTextAreaValues();
 ResetLights();
}
void draw() {
  background(0,50,100);

  if (timeIncrease) time+=timeInc;
  else time-=timeInc;
  if ((time>255)&&(timeIncrease)) timeIncrease=false;
  else if ((!timeIncrease)&&(time<1)) timeIncrease=true;
  
  if (drawMode!=0) DogaClearZBuffer();
  drawPoints();
  if (drawMode!=0) DogaDisplayZBuffer();
  drawText();
  drawLightSource();
}
/***************************************************************/
/****D R A W I N G   A   P O I N T   A N D   Z - B U F F E R****/
/***************************************************************/
void drawPoints() {
 int i=0,j=0,k=0;
 for (i=0;i<nSff;i++) {
   stroke(r[i],g[i],b[i]);
   for (j=0;j<nMesh[i];j++){
      for(k=0;k<nV[i][j]-1;k++){
         if ((drawMode==2)||(drawMode==3)) DogaSetMesh(k,int(objectD[i][j][k][0]),int(objectD[i][j][k][1]),objectD[i][j][k][2],r[i],g[i],b[i],255);
         else {
           drawDogaLineRGB(int(objectD[i][j][k][0]),int(objectD[i][j][k][1]),objectD[i][j][k][2],
                           int(objectD[i][j][k+1][0]),int(objectD[i][j][k+1][1]),objectD[i][j][k+1][2],
                           r[i],g[i],b[i],255);
         }
       }
       if ((drawMode==2)||(drawMode==3)) {
         DogaSetMesh(k,int(objectD[i][j][k][0]),int(objectD[i][j][k][1]),objectD[i][j][k][2],r[i],g[i],b[i],255);
         DogaDrawMesh(nV[i][j],i,j);
       }
       else {
           drawDogaLineRGB(int(objectD[i][j][k][0]),int(objectD[i][j][k][1]),objectD[i][j][k][2],
                           int(objectD[i][j][0][0]),int(objectD[i][j][0][1]),objectD[i][j][0][2],
                           r[i],g[i],b[i],255);
       }
     }
 }
}
void DogaClearZBuffer() {
  for (int i=0;i<xRes;i++)
    for (int j=0;j<yRes;j++) {
      zBuf[i][j] = +1000000;
      cBuf[i][j] = color(0,50,100);
    }
}
void DogaDisplayZBuffer() {
  for (int i=0;i<xRes;i++)
    for (int j=0;j<yRes;j++) {
      stroke(cBuf[i][j]);
      point(i,j);
    }
}
void DogaSetPixel(float x,float y, float z, color c) {
  int i=int(x),j=int(y);
  if ((i<0)||(i>width-1)||(j<0)||(j>height-1)) return;
  if (int(z)>zBuf[i][j]) return;
  zBuf[i][j] = int(z);
  cBuf[i][j] = c;
}
/***************************************************************/
/******* A L L   F U N C T I O N S   O N   L I G H T S  ********/
/***************************************************************/
void DogaSetPixelLight(float x,float y, float z,int Rc,int Gc,int Bc,float[] Nv) {
  int i=int(x),j=int(y),k=0,ambM=0,difM=0,specM=0;
  int Ra=0,Ga=0,Ba=0,Rd=0,Gd=0,Bd=0,Rs=0,Gs=0,Bs=0;
  float Ka=1,Kd=1,Ks=1;
  float[] SpecComp = new float[1];
  if ((i<0)||(i>width-1)||(j<0)||(j>height-1)) return;
  if (int(z)>zBuf[i][j]) return;
  
  k=0;
  while (k<numOfLights) {
    if (ActiveLights[k]==1) {
      if (AMBIENTon[k]) {
        ambM++;
        Ra += Light[k][AMBIENTi][Ri]*Ka*(Light[k][AMBIENTi][Wi]/255);
        Ga += Light[k][AMBIENTi][Gi]*Ka*(Light[k][AMBIENTi][Wi]/255);
        Ba += Light[k][AMBIENTi][Bi]*Ka*(Light[k][AMBIENTi][Wi]/255);
      }
      if (DIFFUSEon[k]) {
        difM++;
        Rd += Light[k][DIFFUSEi][Ri]*Kd*DifComp[k]*(Light[k][DIFFUSEi][Wi]/255);
        Gd += Light[k][DIFFUSEi][Gi]*Kd*DifComp[k]*(Light[k][DIFFUSEi][Wi]/255);
        Bd += Light[k][DIFFUSEi][Bi]*Kd*DifComp[k]*(Light[k][DIFFUSEi][Wi]/255);
      }
      if (SPECULARon[k]) {
        specM++;
        ComputeSpecularVector(SpecComp,i,j,int(z),k,Nv);
        Rs += Light[k][SPECULARi][Ri]*Ks*pow(SpecComp[0],1+20*(Light[k][SPECULARi][Wi]/255));
        Gs += Light[k][SPECULARi][Gi]*Ks*pow(SpecComp[0],1+20*(Light[k][SPECULARi][Wi]/255));
        Bs += Light[k][SPECULARi][Bi]*Ks*pow(SpecComp[0],1+20*(Light[k][SPECULARi][Wi]/255));
      }
    }
    k++;
  }
  k=1;
  if (ambM==0) ambM=1;//not to have division by zero
  else k++;
  if (difM==0) difM=1;//not to have division by zero
  else k++;
  if (specM==0) specM=1;//not to have division by zero
  else k++;
  
  Ra/=ambM; Ga/=ambM; Ba/=ambM;
  Rd/=difM; Gd/=difM; Bd/=difM;
  Rs/=specM; Gs/=specM; Bs/=specM;
  
  zBuf[i][j] = int(z);
  cBuf[i][j] = color((Rc+Ra+Rd+Rs)/k,(Gc+Ga+Gd+Gs)/k,(Bc+Ba+Bd+Bs)/k);
}
void drawLightSource() {
  int k=0;
  if (!showLightSources) return;
  stroke(255,0,0);
  fill(255,0,0);
  float Line=10;
  rectMode(CORNER);
  stroke(255,0,0);
  fill(255,255,255);
  while (k<numOfLights) {
    if (ActiveLights[k]==1) {
      Line = 10-Light[k][POSITIONi][Zi]*0.01;
      rect(Light[k][POSITIONi][Xi],Light[k][POSITIONi][Yi],Line,Line);      
      text("L"+k,Light[k][POSITIONi][Xi],Light[k][POSITIONi][Yi]);
    }
    k++;
  }
}
void ResetLights() {
  numOfActiveLights=0;
  selectedLight=0;
  for (int i=0;i<numOfLights;i++) {
    ActiveLights[i] = 0;
    AMBIENTon[i]=true;
    DIFFUSEon[i]=true;
    SPECULARon[i]=true;
    DifComp[i] = 0;
    //Light ID=i
    //AmbientLight
    Light[i][AMBIENTi][Ri] = 127;
    Light[i][AMBIENTi][Gi] = 127;
    Light[i][AMBIENTi][Bi] = 127;
    Light[i][AMBIENTi][Wi] = 255;
    //DiffuseLight
    Light[i][DIFFUSEi][Ri] = 127;
    Light[i][DIFFUSEi][Gi] = 127;
    Light[i][DIFFUSEi][Bi] = 127;
    Light[i][DIFFUSEi][Wi] = 255;
    //SpecularLight
    Light[i][SPECULARi][Ri] = 127;
    Light[i][SPECULARi][Gi] = 127;
    Light[i][SPECULARi][Bi] = 127;
    Light[i][SPECULARi][Wi] = 50;
    //Position
    Light[i][POSITIONi][Xi] = xRes/2;
    Light[i][POSITIONi][Yi] = yRes/2;
    Light[i][POSITIONi][Zi] = 0;
    Light[i][POSITIONi][Wi] = 1;
  }
  AMBIENTon[0]=true;
  DIFFUSEon[0]=true;
  SPECULARon[0]=true;
  //Light ID=0
  //AmbientLight
  Light[0][AMBIENTi][Ri] = 0;
  Light[0][AMBIENTi][Gi] = 255;
  Light[0][AMBIENTi][Bi] = 255;
  Light[0][AMBIENTi][Wi] = 255;
  //DiffuseLight
  Light[0][DIFFUSEi][Ri] = 255;
  Light[0][DIFFUSEi][Gi] = 0;
  Light[0][DIFFUSEi][Bi] = 255;
  Light[0][DIFFUSEi][Wi] = 255;
  //SpecularLight
  Light[0][SPECULARi][Ri] = 0;
  Light[0][SPECULARi][Gi] = 255;
  Light[0][SPECULARi][Bi] = 247;
  Light[0][SPECULARi][Wi] = 255;
  //Position
  Light[0][POSITIONi][Xi] = 337;
  Light[0][POSITIONi][Yi] = 239;
  Light[0][POSITIONi][Zi] = -50;
  Light[0][POSITIONi][Wi] = 1;

  AMBIENTon[1]=true;
  DIFFUSEon[1]=false;
  SPECULARon[1]=true;
  //Light ID=1
  //AmbientLight
  Light[1][AMBIENTi][Ri] = 0;
  Light[1][AMBIENTi][Gi] = 255;
  Light[1][AMBIENTi][Bi] = 255;
  Light[1][AMBIENTi][Wi] = 255;
  //DiffuseLight
  Light[1][DIFFUSEi][Ri] = 255;
  Light[1][DIFFUSEi][Gi] = 0;
  Light[1][DIFFUSEi][Bi] = 255;
  Light[1][DIFFUSEi][Wi] = 255;
  //SpecularLight
  Light[1][SPECULARi][Ri] = 0;
  Light[1][SPECULARi][Gi] = 255;
  Light[1][SPECULARi][Bi] = 247;
  Light[1][SPECULARi][Wi] = 73;
  //Position
  Light[1][POSITIONi][Xi] = 250;
  Light[1][POSITIONi][Yi] = 212;
  Light[1][POSITIONi][Zi] = -96;
  Light[1][POSITIONi][Wi] = 1;

  AMBIENTon[2]=false;
  DIFFUSEon[2]=false;
  SPECULARon[2]=true;
  //Light ID=1
  //AmbientLight
  Light[2][AMBIENTi][Ri] = 127;
  Light[2][AMBIENTi][Gi] = 255;
  Light[2][AMBIENTi][Bi] = 255;
  Light[2][AMBIENTi][Wi] = 255;
  //DiffuseLight
  Light[2][DIFFUSEi][Ri] = 127;
  Light[2][DIFFUSEi][Gi] = 255;
  Light[2][DIFFUSEi][Bi] = 255;
  Light[2][DIFFUSEi][Wi] = 255;
  //SpecularLight
  Light[2][SPECULARi][Ri] = 255;
  Light[2][SPECULARi][Gi] = 255;
  Light[2][SPECULARi][Bi] = 255;
  Light[2][SPECULARi][Wi] = 60;
  //Position
  Light[2][POSITIONi][Xi] = 308;
  Light[2][POSITIONi][Yi] = 284;
  Light[2][POSITIONi][Zi] = 63;
  Light[2][POSITIONi][Wi] = 1;

  AMBIENTon[3]=true;
  DIFFUSEon[3]=true;
  SPECULARon[3]=true;
  //Light ID=3
  //AmbientLight
  Light[3][AMBIENTi][Ri] = 0;
  Light[3][AMBIENTi][Gi] = 255;
  Light[3][AMBIENTi][Bi] = 255;
  Light[3][AMBIENTi][Wi] = 255;
  //DiffuseLight
  Light[3][DIFFUSEi][Ri] = 255;
  Light[3][DIFFUSEi][Gi] = 0;
  Light[3][DIFFUSEi][Bi] = 255;
  Light[3][DIFFUSEi][Wi] = 255;
  //SpecularLight
  Light[3][SPECULARi][Ri] = 0;
  Light[3][SPECULARi][Gi] = 255;
  Light[3][SPECULARi][Bi] = 247;
  Light[3][SPECULARi][Wi] = 255;
  //Position
  Light[3][POSITIONi][Xi] = 261;
  Light[3][POSITIONi][Yi] = 291;
  Light[3][POSITIONi][Zi] = 44;
  Light[3][POSITIONi][Wi] = 1;
  
  AMBIENTon[4]=true;
  DIFFUSEon[4]=true;
  SPECULARon[4]=true;
  //Light ID=4
  //AmbientLight
  Light[4][AMBIENTi][Ri] = 0;
  Light[4][AMBIENTi][Gi] = 255;
  Light[4][AMBIENTi][Bi] = 255;
  Light[4][AMBIENTi][Wi] = 255;
  //DiffuseLight
  Light[4][DIFFUSEi][Ri] = 255;
  Light[4][DIFFUSEi][Gi] = 0;
  Light[4][DIFFUSEi][Bi] = 255;
  Light[4][DIFFUSEi][Wi] = 255;
  //SpecularLight
  Light[4][SPECULARi][Ri] = 0;
  Light[4][SPECULARi][Gi] = 255;
  Light[4][SPECULARi][Bi] = 247;
  Light[4][SPECULARi][Wi] = 255;
  //Position
  Light[4][POSITIONi][Xi] = 340;
  Light[4][POSITIONi][Yi] = 191;
  Light[4][POSITIONi][Zi] = -148;
  Light[4][POSITIONi][Wi] = 1;
}
void ComputeDiffuseVector(float xP,float yP,float zP,float[] N) {
  float[] L = new float[3];
  int k=0;
    //first determine L as the Ligth vector
  while (k<numOfLights) {
    if ((ActiveLights[k]==1)&&(DIFFUSEon[k])) {
      L[Xi] = Light[k][POSITIONi][Xi] - xP;
      L[Yi] = Light[k][POSITIONi][Yi] - yP;
      L[Zi] = Light[k][POSITIONi][Zi] - zP;
      DogaMakeUnitVector(L);
      DifComp[k] = DogaDotProduct(N,L);
    }
    k++;
  }
}
void ComputeSpecularVector(float SpecComp[],float xP,float yP,float zP,int LightID,float[] N) {
  float[] L = new float[3];
  int i=0;
    //first determine L as the Ligth vector
  L[Xi] = Light[LightID][POSITIONi][Xi] - xP;
  L[Yi] = Light[LightID][POSITIONi][Yi] - yP;
  L[Zi] = Light[LightID][POSITIONi][Zi] - zP;
  DogaMakeUnitVector(L);
  SpecComp[0] = DogaDotProduct(N,L);
}
/***************************************************************/
/****** 3 D   P O L Y G O N   R A S T E R I Z A T I O N  *******/
/***************************************************************/
void DogaDrawMesh(int n,int objNum,int polyNum) {
  int k=0,difZ=2;
  float[] V1=new float[4];
  float[] V2=new float[4];
  float[] V3=new float[4];
  V1[0] = myMesh[1][0] - myMesh[0][0];
  V1[1] = myMesh[1][1] - myMesh[0][1];
  V1[2] = myMesh[1][2] - myMesh[0][2];
  V1[3] = 1;
  V2[0] = myMesh[n-1][0] - myMesh[0][0];
  V2[1] = myMesh[n-1][1] - myMesh[0][1];
  V2[2] = myMesh[n-1][2] - myMesh[0][2];
  V2[3] = 1;
  DogaMakeUnitVector(V1);
  DogaMakeUnitVector(V2);
  V3 = DogaCrossProduct(V1,V2);
  if ((V3[2]>0)&&(objNum==selectedObject)) {
    meshTextArea[selectedObject][polyNum][0] = 0;
    meshTextArea[selectedObject][polyNum][1] = 0;
    meshTextArea[selectedObject][polyNum][2] = -1;
    return;
  }
  meshXmid /= n; meshYmid /= n; meshZmid /= n;
  //Compute Diffuse Component Before Going To Render
  if (drawMode==3) {
    ComputeDiffuseVector(meshXmid,meshYmid,meshZmid,V3);
    DogaTriangulateAndRaster(myMesh,n,myColor,polyNum,V3);
  }
  if (drawWireFrames!=0) {
    for(k=0;k<n-1;k++)
      drawDogaLineCOL(int(myMesh[k][0]),int(myMesh[k][1]),myMesh[k][2]-difZ,
                      int(myMesh[k+1][0]),int(myMesh[k+1][1]),myMesh[k+1][2]-difZ,
                      myColor);
    drawDogaLineCOL(int(myMesh[k][0]),int(myMesh[k][1]),myMesh[k][2]-difZ,
                    int(myMesh[0][0]),int(myMesh[0][1]),myMesh[0][2]-difZ,
                    myColor);
  }
  if (objNum==selectedObject) {
    meshTextArea[selectedObject][polyNum][0] = meshXmid;
    meshTextArea[selectedObject][polyNum][1] = meshYmid;
    meshTextArea[selectedObject][polyNum][2] = 1;
  }
}
void DogaTriangulateAndRaster(float[][] vList,int n,color col,int polyNum,float[] Nv) {
  int i=0,j=0,k=0,a=0,b=0,c=0;
  int maxInc=0;
  if (n>15) return;
  if (n==2) {
    drawDogaLineCOL(int(vList[0][0]),int(vList[0][1]),vList[0][2],
                    int(vList[1][0]),int(vList[1][1]),vList[1][2],
                    col);
    return;
  }
  if (n==3) {
    DogaRasterTriangle(vList[0],vList[1],vList[2],col,polyNum,Nv);
    return;
  }
  if (n==4) maxInc=2;
  else if (n<=8) maxInc=4;
  else maxInc=8;
  
  for(i=2;i<=maxInc;i*=2){
    j=0;
    while(j<n) {
      a=j; b=j+i/2; c=j+i;
      if ((b>=n)&&(c>=n)) j=n+1;
      else {
        if (c>=n) c=0;
        DogaRasterTriangle(vList[a],vList[b],vList[c],col,polyNum,Nv);
      }
      j+=i;
    }
  }
}
void DogaRasterTriangle(float[] P0,float[] P1,float[] P2,color c,int polyNum,float[] Nv) {
  float P[][] = new float[3][3],Cv1[] = new float[3],Cv2[] = new float[3];
  float xInc[]=new float[3],yInc[]=new float[3],zInc[]=new float[3],zRowScale,xRowScale;
  float xRowInc[][]=new float[2][2],zRowInc[][]=new float[2][2];
  
  int loopStart[]=new int[2],loopEnd[]=new int[2];
  float xRowStart,xRowEnd,zRowStart,zRowEnd;

  int i=0,midPoint=1;//midPoint will be 1 or to according to which point has the change of dec/inc
  float x=0,y=0,z=0;//for rendering and "for-loop" values

  int from=0,to=1,loopN=0;
  int fr0to1=0,fr0to2=1,fr1to2=2;
  
  for(i=0;i<3;i++) {
    P[0][i] = P0[i];
    P[1][i] = P1[i];
    P[2][i] = P2[i];
  }
  SortPoints(P);//P[0] with the highest Y, P1 with a smaller X and P2 with the bigger X
  
  //now check if the triangle is fine for the algorithm to draw.If not make them fine and recursively draw.
  Cv1[0] = P[0][0] - P[1][0];//0to1
  Cv1[1] = P[1][1] - P[0][1];//0to1  
  Cv2[0] = P[2][0] - P[1][0];//2to1
  Cv2[1] = P[1][1] - P[2][1];//2to1
  if ((Cv2[0]<Cv1[0])&&(P[2][1]<P[1][1]-Cv2[0]*(Cv1[1]/Cv1[0]))) {
    //this means the triangle is not fine. so assign new 2 triangles and draw them
    Cv1[0] = (P[0][0] + P[1][0])/2;
    Cv1[1] = (P[0][1] + P[1][1])/2;
    Cv1[2] = (P[0][2] + P[1][2])/2;
    DogaRasterTriangle(P[2],P[1],Cv1,c,polyNum,Nv);
    DogaRasterTriangle(P[0],P[2],Cv1,c,polyNum,Nv);
    return;
  }
  else if ((P[1][0]>P[0][0])&&(P[1][1]<P[2][1])) {
    //this ALSO means the triangle is not fine. so assign new 2 triangles and draw them
    Cv1[0] = P[0][0] + ((P[0][1]-P[1][1])/(P[0][1]-P[2][1]))*(P[2][0]-P[0][0]);
    Cv1[1] = P[1][1];
    Cv1[2] = P[0][2] + ((P[0][1]-P[1][1])/(P[0][1]-P[2][1]))*(P[2][2]-P[0][2]);
    DogaRasterTriangle(P[0],P[1],Cv1,c,polyNum,Nv);
    DogaRasterTriangle(P[1],P[2],Cv1,c,polyNum,Nv);
    return;
  }
  // FIND THE HEIGHT DIFFERENCES AMONG THE POINTS
  if ((P[0][1]-P[1][1])!=0) yInc[0] = -1/(P[0][1]-P[1][1]); else yInc[fr0to1]=0;//0->1
  if ((P[0][1]-P[2][1])!=0) yInc[1] = -1/(P[0][1]-P[2][1]); else yInc[fr0to2]=0;//0->2
  if ((P[1][1]-P[2][1])!=0) yInc[2] = -1/(P[1][1]-P[2][1]); else yInc[fr1to2]=0;//1->2

  //FIND THE X AND Z DIFFERENCES AMONG THE POINTS
  xInc[fr0to1] = (P[0][0]-P[1][0])*yInc[fr0to1];//for line 0->1
  zInc[fr0to1] = (P[0][2]-P[1][2])*yInc[fr0to1];

  xInc[fr0to2] = (P[0][0]-P[2][0])*yInc[fr0to2];//for line 0->2
  zInc[fr0to2] = (P[0][2]-P[2][2])*yInc[fr0to2];

  xInc[fr1to2] = (P[1][0]-P[2][0])*yInc[fr1to2];//for line 1->2
  zInc[fr1to2] = (P[1][2]-P[2][2])*yInc[fr1to2];

  loopN=0;
  if (yInc[fr0to1]==0) {//the first 2 points are on the same y value
  // the first start point is the second point P[1]
    xRowStart = P[1][0];
    zRowStart = P[1][2];
  //no increment for x and z values
  //xInc[fr0to1]=zInc[fr0to1]=0;
  }
  else {// the first two points have different y values, in other words P[1][y]<P[0][y]
  // the first start point is the first point P[0]
    xRowStart = P[0][0];
    zRowStart = P[0][2];
  }
  // no matter what, the end points will be of P[0]
  xRowEnd = P[0][0];
  zRowEnd = P[0][2];

  //loops will be based on Y values, hence the start point is P[0][1] ->
  loopStart[loopN] = int(P[0][1]);
  //Row increments for the first run
  xRowInc[from][loopN] = xInc[fr0to1];//from
  xRowInc[to][loopN]   = xInc[fr0to2];//to
  zRowInc[from][loopN] = zInc[fr0to1];//from
  zRowInc[to][loopN]	 = zInc[fr0to2];//to
  loopN=1;
  //P[1][x]<P[2][x] but what about the y values??
  if (P[1][1]<P[2][1]) {// so P[1] is at a higher point
    //First loop will start with P[0][y] and end with P[1][y]
    //Second loop will start with P[1][y]+1 and end with P[2][y]
    midPoint          = 1;
    loopEnd[0]       = int(P[1][1]);
    loopStart[loopN]  = int(P[1][1]+1);
    loopEnd[loopN]    = int(P[2][1]);
    //Row increments for the second run
    xRowInc[from][loopN] = xInc[fr1to2];//from
    xRowInc[to][loopN]   = xInc[fr0to2];//to
    zRowInc[from][loopN] = zInc[fr1to2];//from
    zRowInc[to][loopN]   = zInc[fr0to2];//to
  }
  else {//P[2] is at a higher point
  	//First loop will start with P[0][y] and end with P[2][y]
	//Second loop will start with P[2][y]-1 and end with P[1][y]
    midPoint         = 2;
    loopEnd[0]       = int(P[2][1]);
    loopStart[loopN] = int(P[2][1]+1);
    loopEnd[loopN]   = int(P[1][1]);
    //Row increments for the second run
    xRowInc[from][loopN] = xInc[fr0to1];//from
    xRowInc[to][loopN]   = xInc[fr1to2];//to
    zRowInc[from][loopN] = zInc[fr0to1];//from
    zRowInc[to][loopN]   = zInc[fr1to2];//to
  }

  for (i=0;i<2;i++) {//there will be 2 runs, "i" will indicate the loop number
    y=loopStart[i];
    if (i==1) {//this means the inc/dec will change
      if (midPoint==1) {xRowStart=P[1][0];zRowStart=P[1][2];}
      else {xRowEnd=P[2][0];zRowEnd=P[2][2];}
    }
    while (y<=loopEnd[i]) {//y will increase for each scan line
      z=zRowStart;
      //find the increment for z values during the scan line
      if ((xRowEnd==xRowStart)&&(zRowEnd==zRowStart)) {xRowScale=1; zRowScale = 0;}//(zRowEnd-zRowStart)/(loopEnd[i]-loopStart[i]);
      else if (absD(xRowEnd-xRowStart)>0) zRowScale = (zRowEnd-zRowStart)/(xRowEnd-xRowStart);
      else zRowScale = 1/(zRowEnd-zRowStart);
      x=xRowStart;
      while (x<=xRowEnd) {
        DogaSetPixel(x,y,z,color(fillR,fillG,fillB));
        if (numOfActiveLights>0) DogaSetPixelLight(x,y,z,fillR,fillG,fillB,Nv);
        z = z+zRowScale;
        x = x+=1;
      }
      xRowStart = xRowStart - xRowInc[from][i];
      xRowEnd   = xRowEnd   - xRowInc[to][i];
      zRowStart = zRowStart - zRowInc[from][i];
      zRowEnd   = zRowEnd   - zRowInc[to][i];
      y+=1;
    }
  }
  return;
}
void SortPoints(float P[][]){
  int i=0,j=0,k=0,ii=0,maxY[]=new int[2];
  float x=0,y=0,z=0;
  maxY[0]=maxY[1]=height+1;
  for(i=0;i<3;i++) {
    j=(i+1)%3;
    k=(i+2)%3;
    if ((P[i][1]<=P[j][1])&&(P[i][1]<=P[k][1])) 
    if (ii<1)  maxY[ii++]=i;
  }
  if ((ii>1)&&(P[maxY[0]][0]>P[maxY[1]][0])) {//so second one will get the values of last one
    x = P[0][0];		y = P[0][1];		  z = P[0][2];
    P[0][0] = P[maxY[1]][0];	P[0][1] = P[maxY[1]][1];  P[0][2] = P[maxY[1]][2];
    P[maxY[1]][0] = x;		P[maxY[1]][1] = y;	  P[maxY[1]][2] = z;
  }
  else {
    x = P[0][0];		y = P[0][1];		  z = P[0][2];
    P[0][0] = P[maxY[0]][0];	P[0][1] = P[maxY[0]][1];  P[0][2] = P[maxY[0]][2];
    P[maxY[0]][0] = x;		P[maxY[0]][1] = y;	  P[maxY[0]][2] = z;
  }
  if (P[1][0]>P[2][0]) {//so second one will get the values of last one
    x = P[2][0];	y = P[2][1];  	    z = P[2][2];
    P[2][0] = P[1][0];	P[2][1] = P[1][1];  P[2][2] = P[1][2];
    P[1][0] = x;	P[1][1] = y;	    P[1][2] = z;
  }
}
/***************************************************************/
/********* L I N E   D R A W I N G   F U N C T I O N S *********/
/***************************************************************/
void drawDogaLineRGB(int x0,int y0,float z0,int x1,int y1,float z1,int R,int G,int B,int W) {
  int xs,xf,ys,yf;
  float zs=0,zf=0,zDif=0,z=0,m=1;
  int d=1;
  int i,j,k;
  // first lets make sure that xf>xs
  if (x1>x0) {xs=x0;xf=x1;ys=y0;yf=y1;zs=z0;zf=z1;}
  else {xs=x1;xf=x0;ys=y1;yf=y0;zs=z1;zf=z0;}
  if (yf<ys) d=-1;
  
  int dx=xf-xs;
  int dy=(yf-ys)*d;
  int dif=dy-dx;
    
  point(xs,ys);
   
  if (dx>=dy) { // IF X-BASED
    i=xs;j=ys;zDif=(zf-zs)/dx;z=zs;
    while (i!=xf) {
      if (dif>0) {i++;j+=d;dif+=dy-dx;}
      else {i++;dif+=dy;}
      
      m=1;
//      m=absD(float(dif/dx));
      if (drawMode==0) {//SIMPLE MODE
        if (drawWireFrames==1) {stroke(R,G,B,W); point(i,j);}
        else if (drawWireFrames==2) {
          stroke(R*m,G*m,B*m,W);
          point(i,j);
          stroke(R*(1-m),G*(1-m),B*(1-m),W); //ANTI-ALIASED COLOR IS THE HALF BRIGHT OF THE SAME COLOR
          point(i,j-1);
        }
      }
      else {// OTHER MODES
        if (drawWireFrames==1) DogaSetPixel(i,j,z,color(R,G,B,W)); 
        else {
          DogaSetPixel(i,j,z,color(R*m,G*m,B*m,W)); 
          DogaSetPixel(i,j-1,z,color(R*(1-m),G*(1-m),B*(1-m),W)); 
        }
      }
      z+=zDif;
    }
  }
  else { // IF Y-BASED
    i=xs;j=ys;zDif=(zf-zs)/dy;z=zs;
    while (j!=yf) {
      if (dif>0) {i++;j+=d;dif+=dx-dy;}
      else {j+=d;dif+=dx;}

      m=0.7;
//    m=absD(float(dif/dy));
      if (drawMode==0) {//SIMPLE MODE
        if (drawWireFrames==1) {stroke(R,G,B,W); point(i,j);}
        else if (drawWireFrames==2) {
          stroke(R*m,G*m,B*m,W);
          point(i,j);
          stroke(R*(1-m),G*(1-m),B*(1-m),W); //ANTI-ALIASED COLOR IS THE HALF BRIGHT OF THE SAME COLOR
          point(i,j-1);
        }
      }
      else {// OTHER MODES
        if (drawWireFrames==1) DogaSetPixel(i,j,z,color(R,G,B,W)); 
        else {
          DogaSetPixel(i,j,z,color(R*m,G*m,B*m,W)); 
          DogaSetPixel(i,j-1,z,color(R*(1-m),G*(1-m),B*(1-m),W)); 
        }
      }
      z+=zDif;
    }
  }
}
void drawDogaLineCOL(int x0,int y0,float z0,int x1,int y1,float z1,color c) {
  int xs,xf,ys,yf;
  float zs=0,zf=0,zDif=0,z=0;
  int i,j,k,d=1;
  // first lets make sure that xf>xs
  if (x1>x0) {xs=x0;xf=x1;ys=y0;yf=y1;zs=z0;zf=z1;}
  else {xs=x1;xf=x0;ys=y1;yf=y0;zs=z1;zf=z0;}
  if (yf<ys) d=-1;
  
  int dx=xf-xs;
  int dy=(yf-ys)*d;
  int dif=dy-dx;

  stroke(c);    
  point(xs,ys);  
  if (dx>=dy) { // IF X-BASED
    i=xs;j=ys;zDif=(zf-zs)/dx;z=zs;
    while (i!=xf) {
      if (dif>0) {i++;j+=d;dif+=dy-dx;}
      else {i++;dif+=dy;}
      if (drawMode==0) point(i,j); //simple mode
      else DogaSetPixel(i,j,z,c);// zBufferMode or triangulateMode
      z+=zDif;
    }
  }
  else { // IF Y-BASED
    i=xs;j=ys;zDif=(zf-zs)/dy;z=zs;
    while (j!=yf) {
      if (dif>0) {i++;j+=d;dif+=dx-dy;}
      else {j+=d;dif+=dx;}
      if (drawMode==0) point(i,j);//simple mode 
      else DogaSetPixel(i,j,z,c);// zBufferMode or triangulateMode
      z+=zDif;
    }
  }
}
/***************************************************************/
/********* E X T R A   N E E D E D   F U N C T I O N S *********/
/***************************************************************/
//FOR FLOATING POINT ABSOLUTE VALUE :)
float absD(float x) {
  if (x>=0) return x;
  return -x;
}
//FOR DEBUGGING PURPOSES
void PrintPoints(String name,float p[][],int row,int col) {
  int i=0,j=0;
  println("Printing "+name);
  for (i=0;i<row;i++) {
    print("  ");
    for(j=0;j<col;j++)
      print("["+p[i][j]+"],");
    println();
  }
}
/****************************************************************/
/*O P E R A T I O N S   O F   R E A D I N G    T H E   F I L E S*/
/****************************************************************/
void readInEachSff() {
  int i=0,j=0,k=0,cnt=0;
  String sff[];
  nMesh = new int[nSff];
  nV = new int[nSff][];
  for(i=0;i<nSff;i++){
    cnt=0;
    sff = loadStrings(sffName[i]);
    nMesh[i] = int(sff[cnt++]);
    objectS[i] = new float[nMesh[i]][][];
    objectD[i] = new float[nMesh[i]][][];
    nV[i] = new int[nMesh[i]];
    DogaRotateFX(rx[i],ry[i],rz[i]);
    DogaScaleFX(sx[i],sy[i],sz[i]);
    DogaTranslateFX(tx[i],ty[i],tz[i]);
    meshTextArea[i] = new int[nMesh[i]][];
    for (j=0;j<nMesh[i];j++) {
      nV[i][j] = int(trim(sff[cnt++]));
      meshTextArea[i][j] = new int[3];
      objectS[i][j] = new float[nV[i][j]][4];
      objectD[i][j] = new float[nV[i][j]][4];
      for (k=0;k<nV[i][j];k++) {// now read every point in mesh
        line1 = split(trim(sff[cnt++]),' ');
        objectS[i][j][k][0] = float(line1[0]);
        objectS[i][j][k][1] = float(line1[1]);
        objectS[i][j][k][2] = float(line1[2]);
        objectS[i][j][k][3] = 1;
      }//k-nV
    }//j-nMesh
    ApplyMatrix(i);
  }//i-nSff 
}
void readInSffs(){
 int i=0,n=nSff;
 r = new int[n]; g = new int[n]; b = new int[n];
 rx = new float[n]; ry = new float[n]; rz = new float[n];
 sx = new float[n]; sy = new float[n]; sz = new float[n];
 tx = new float[n]; ty = new float[n]; tz = new float[n];
 sffName = new String[n];
 for (i=0;i<n;i++){
   line1 = split(data[i+3],' ');
   r[i] = int(line1[0]);
   g[i] = int(line1[1]);
   b[i] = int(line1[2]);
   rx[i] = float(line1[3]);ry[i]=float(line1[4]);rz[i] = float(line1[5]);
   sx[i] = float(line1[6]);sy[i]=float(line1[7]);sz[i] = float(line1[8]);
   tx[i] = float(line1[9]);ty[i]=float(line1[10]);tz[i] = float(line1[11]);
   sffName[i] = line1[12];
   projectionMode[i]=1;
 }
 readInEachSff();
}
void readInBasicFile(){
 int i=0;
 data = loadStrings(fileName[activeFile]);
 nSff=data.length-3;
 objectS = new float[nSff][][][];
 objectD = new float[nSff][][][];
 meshTextArea = new int[nSff][][];
 projectionMode = new int[nSff]; 
 line1 = split(data[0],' ');
 xRes=int(line1[0]); yRes=int(line1[1]);
 zBuf = new int[xRes][yRes];
 cBuf = new color[xRes][yRes];
 line1 = split(data[1],' ');
 pM = new float[4];uM = new float[4];vM = new float[4];nM = new float[4];
 pM[0]=float(line1[0]);pM[1]=float(line1[1]); pM[2]=float(line1[2]);pM[3]=1;
 uM[0]=float(line1[3]);uM[1]=float(line1[4]); uM[2]=float(line1[5]);uM[3]=1;
 vM[0]=float(line1[6]);vM[1]=float(line1[7]); vM[2]=float(line1[8]);vM[3]=1;
 nM[0]=float(line1[9]);nM[1]=float(line1[10]);nM[2]=float(line1[11]);nM[3]=1;
 DogaCameraFX(pM,uM,vM,nM);
 line1 = split(data[2],' ');
 near = float(line1[0]);  far = float(line1[1]);
 top = float(line1[2]);  bottom = float(line1[3]);
 left = float(line1[4]); right = float(line1[5]);
 DogaProjectionFX(1,near,far,top,bottom,left,right);
 readInSffs();
}
/****************************************************************/
/*********** T E X T   A R E A    O P E R A T I O N S ***********/
/****************************************************************/
int fI=33,mI=7;//FIRST INDEX
void setTextAreaValues() {
  int i=0,j=0;
  textArea = new int[41][4];
  for (i=0;i<14;i++) {
    textArea[i][0]=int(width*0.75);
    textArea[i][1]=width;
    textArea[i][2]=j;
    textArea[i][3]=j+20;
    j+=20;
  }
  j=0;
  for (i=14;i<30;i++) {
    textArea[i][0]=0;
    textArea[i][1]=int(width*0.27);
    textArea[i][2]=j;
    textArea[i][3]=j+20;
    j+=20;
  }
  j=height-(mI+2)*20;
  for (i=fI;i<=fI+mI;i++) {
    textArea[i][0]=0;
    textArea[i][1]=int(width-1);
    textArea[i][2]=j;
    textArea[i][3]=j+20;
    j+=20;
  }
}
void drawText() {
  fill(0,255,0);
  //First the object selected will be mentioned
  text("Object->"+sffName[selectedObject],textArea[0][0],textArea[0][3]);
  //Second projectionMode
  if (projectionMode[selectedObject]==1) text("ProjMode->Perspective",textArea[1][0],textArea[1][3]);
  else  text("ProjMode->Orthogonal",textArea[1][0],textArea[1][3]);

  text("Rotation Values->",textArea[2][0],textArea[2][3]);
  text("Rx=("+rx[selectedObject]+")",textArea[3][0],textArea[3][3]);
  text("Ry=("+ry[selectedObject]+")",textArea[4][0],textArea[4][3]);
  text("Rz=("+rz[selectedObject]+")",textArea[5][0],textArea[5][3]);
  
  text("Scale Values->",textArea[6][0],textArea[6][3]);
  text("Sx=("+sx[selectedObject]+")",textArea[7][0],textArea[7][3]);
  text("Sy=("+sy[selectedObject]+")",textArea[8][0],textArea[8][3]);
  text("Sz=("+sz[selectedObject]+")",textArea[9][0],textArea[9][3]);
  
  text("Translate Values->",textArea[10][0],textArea[10][3]);
  text("Tx=("+tx[selectedObject]+")",textArea[11][0],textArea[11][3]);
  text("Ty=("+ty[selectedObject]+")",textArea[12][0],textArea[12][3]);
  text("Tz=("+tz[selectedObject]+")",textArea[13][0],textArea[13][3]);

  text("File->"+fileName[activeFile],textArea[14][0],textArea[14][3]);

  fill(255,255,255);
  text("click on any text in screen.",textArea[14][1]+width*0.1,textArea[14][3]);
  text("then press + and - to change values.",textArea[14][1]+width*0.05,textArea[15][3]);
  fill(0,255,0);

  text("Camera Values->",textArea[15][0],textArea[15][3]);

  text("Px=("+pM[0]+")",textArea[16][0],textArea[16][3]);
  text("Py=("+pM[1]+")",textArea[17][0],textArea[17][3]);
  text("Pz=("+pM[2]+")",textArea[18][0],textArea[18][3]);
  
  text("Ux=("+uM[0]+")",textArea[19][0],textArea[19][3]);
  text("Uy=("+uM[1]+")",textArea[20][0],textArea[20][3]);
  text("Uz=("+uM[2]+")",textArea[21][0],textArea[21][3]);

  text("Vx=("+vM[0]+")",textArea[22][0],textArea[22][3]);
  text("Vy=("+vM[1]+")",textArea[23][0],textArea[23][3]);
  text("Vz=("+vM[2]+")",textArea[24][0],textArea[24][3]);

  text("Nx=("+nM[0]+")",textArea[25][0],textArea[25][3]);
  text("Ny=("+nM[1]+")",textArea[26][0],textArea[26][3]);
  text("Nz=("+nM[2]+")",textArea[27][0],textArea[27][3]);

  if (drawWireFrames==0) text("Not Drawing Wires.",textArea[28][0],textArea[28][3]);
  else if (drawWireFrames==1) text("Drawing Jaggy-W.",textArea[28][0],textArea[28][3]);
  else if (drawWireFrames==2) text("Drawing Anti-Aliased-W.",textArea[28][0],textArea[28][3]);

  if (showLightSources) text("Show Active Lights.",textArea[29][0],textArea[29][3]);
  else text("Dont Show Active Lights.",textArea[29][0],textArea[29][3]);

  fill(90+time/2,90+time/2,0);
  if (warningText!=null) text(warningText,textArea[fI+mI-6][0],textArea[fI+mI-6][3]);    

  fill(255,255,255);
  if (drawMode==0) text("Drawing in simple mode.(Click to change mode)",textArea[fI+mI-5][0],textArea[fI+mI-5][3]);
  if (drawMode==1) text("Drawing in Z-Buffer mode.(Click to change mode)",textArea[fI+mI-5][0],textArea[fI+mI-5][3]);
  if ((drawMode==2)&&(numDisplay)) text("Drawing in back-face culling mode.(Click to change mode or press 'n-N' to deactivate numbers)",textArea[fI+mI-5][0],textArea[fI+mI-5][3]);
  if ((drawMode==2)&&(!numDisplay)) text("Drawing in back-face culling mode.(Click to change mode or press 'n-N' to activate numbers)",textArea[fI+mI-5][0],textArea[fI+mI-5][3]);
  if ((drawMode==3)&&(numDisplay)) text("Drawing in lighting mode.(Click to change mode or press 'n-N' to deactivate numbers)",textArea[fI+mI-5][0],textArea[fI+mI-5][3]);
  if ((drawMode==3)&&(!numDisplay)) text("Drawing in lighting mode.(Click to change mode or press 'n-N' to activate numbers)",textArea[fI+mI-5][0],textArea[fI+mI-5][3]);

  if (((drawMode==2)||(drawMode==3))&&(numDisplay)) {
    stroke(0,255,0);
    for (int j=0;j<nMesh[selectedObject];j++)
      if (meshTextArea[selectedObject][j][2]>0)
        text(j,meshTextArea[selectedObject][j][0],meshTextArea[selectedObject][j][1]);
  }

  if (ActiveLights[selectedLight]==1) {
    if (drawMode!=3) text("Light_"+selectedLight+" is on.Click 'L-l' to turn off the light.(To see effects switch to lighting mode)",textArea[fI+mI-4][0],textArea[fI+mI-4][3]);
    else text("Light_"+selectedLight+" is on.Click 'L-l' to turn off the light.(To move the light press 'm or M'.)",textArea[fI+mI-4][0],textArea[fI+mI-4][3]);

    fill(Light[selectedLight][AMBIENTi][Ri],Light[selectedLight][AMBIENTi][Gi],Light[selectedLight][AMBIENTi][Bi],100+Light[selectedLight][AMBIENTi][Wi]);
    if (moveLight) {
      fill(30,30,30);     
      if (AMBIENTon[selectedLight])
      text("To control these values press 'm or M' again.]Amb.R="+Light[selectedLight][AMBIENTi][Ri]+
           "/ Amb.G="+Light[selectedLight][AMBIENTi][Gi]+
           "/ Amb.B="+Light[selectedLight][AMBIENTi][Bi]+
           "/ Amb.W="+Light[selectedLight][AMBIENTi][Wi],textArea[fI+mI-3][0],textArea[fI+mI-3][3]);
      else text("AMBIENT off.(press 'a or A' to turn it on)",textArea[fI+mI-3][0],textArea[fI+mI-3][3]);
    }
    else {
      if (AMBIENTon[selectedLight])
      text("Amb.R="+Light[selectedLight][AMBIENTi][Ri]+
           "/ Amb.G="+Light[selectedLight][AMBIENTi][Gi]+
           "/ Amb.B="+Light[selectedLight][AMBIENTi][Bi]+
           "/ Amb.W="+Light[selectedLight][AMBIENTi][Wi]+"(press 'a or A' to turn it off)",textArea[fI+mI-3][0],textArea[fI+mI-3][3]);
      else text("AMBIENT off.(press 'a or A' to turn it on)",textArea[fI+mI-3][0],textArea[fI+mI-3][3]);
    }
    fill(Light[selectedLight][DIFFUSEi][Ri],Light[selectedLight][DIFFUSEi][Gi],Light[selectedLight][DIFFUSEi][Bi],100+Light[selectedLight][DIFFUSEi][Wi]);
    if (moveLight) {      
      fill(30,30,30);     
      if (DIFFUSEon[selectedLight])
      text("To control these values press 'm or M' again.]Dif.R="+Light[selectedLight][DIFFUSEi][Ri]+
           "/ Dif.G="+Light[selectedLight][DIFFUSEi][Gi]+
           "/ Dif.B="+Light[selectedLight][DIFFUSEi][Bi]+
           "/ Dif.W="+Light[selectedLight][DIFFUSEi][Wi],textArea[fI+mI-2][0],textArea[fI+mI-2][3]);
      else text("DIFFUSE off.",textArea[fI+mI-2][0],textArea[fI+mI-2][3]);
    }
    else {
      if (DIFFUSEon[selectedLight])
      text("Dif.R="+Light[selectedLight][DIFFUSEi][Ri]+
           "/ Dif.G="+Light[selectedLight][DIFFUSEi][Gi]+
           "/ Dif.B="+Light[selectedLight][DIFFUSEi][Bi]+
           "/ Dif.W="+Light[selectedLight][DIFFUSEi][Wi]+"(press 'd or D' to turn it off)",textArea[fI+mI-2][0],textArea[fI+mI-2][3]);
      else text("DIFFUSE off.(press 'd or D' to turn it on)",textArea[fI+mI-2][0],textArea[fI+mI-2][3]);
    }
    
    fill(Light[selectedLight][SPECULARi][Ri],Light[selectedLight][SPECULARi][Gi],Light[selectedLight][SPECULARi][Bi],255);
    if (moveLight) {
      fill(30,30,30);     
      if (SPECULARon[selectedLight])
      text("To control these values press 'm or M' again.]Spc.R="+Light[selectedLight][SPECULARi][Ri]+
           "/ Spc.G="+Light[selectedLight][SPECULARi][Gi]+
           "/ Spc.B="+Light[selectedLight][SPECULARi][Bi]+
           "/ Spc.n="+(1+20*(Light[selectedLight][SPECULARi][Wi]/255)),textArea[fI+mI-1][0],textArea[fI+mI-1][3]);
      else text("SPECULAR off.",textArea[fI+mI-1][0],textArea[fI+mI-1][3]);
    }
    else { 
      if (SPECULARon[selectedLight])
      text("Spc.R="+Light[selectedLight][SPECULARi][Ri]+
           "/ Spc.G="+Light[selectedLight][SPECULARi][Gi]+
           "/ Spc.B="+Light[selectedLight][SPECULARi][Bi]+
           "/ Spc.n="+(1+20*(Light[selectedLight][SPECULARi][Wi]/255))+"(press 's or S' to turn it off)",textArea[fI+mI-1][0],textArea[fI+mI-1][3]);
      else text("SPECULAR off.(press 's or S' to turn it on)",textArea[fI+mI-1][0],textArea[fI+mI-1][3]);
    }
    fill(0,255,0);
    text("Lx="+Light[selectedLight][POSITIONi][Xi]+
         "/ Ly="+Light[selectedLight][POSITIONi][Yi]+
         "/ Lz="+Light[selectedLight][POSITIONi][Zi],textArea[fI+mI-0][0],textArea[fI+mI-0][3]);
  }
  else {
    if (drawMode!=3) text("Light_"+selectedLight+" is off.Click 'L-l' to turn on the light.(To see effects turn light on & switch to lighting mode)",textArea[fI+mI-4][0],textArea[fI+mI-4][3]);
    else text("Light_"+selectedLight+" is off.Click 'L-l' to turn on the light.(To see effects you need to turn at least 1 light on.)",textArea[fI+mI-4][0],textArea[fI+mI-4][3]);
  }
  drawTextAreas();
}
void drawTextAreas() {
  int i=0,j=0;
  stroke(25,75,125);
  noFill();
  rectMode(CORNERS);
  for (i=0;i<30;i++)
    rect(textArea[i][0],textArea[i][2],textArea[i][1],textArea[i][3]);
  for (i=fI+1;i<fI+mI+1;i++)
    rect(textArea[i][0],textArea[i][2],textArea[i][1],textArea[i][3]);
}
/***************************************************************/
/** M O U S E    A N D   K E Y B O A R D   O P E R A T I O N S**/
/***************************************************************/
void keyPressed() {
  int i=0;
  if (key=='0') drawMode=0;
  else if (key=='1') drawMode=1;
  else if (key=='2') drawMode=2;
  else if (key=='3') drawMode=3;
  else if ((key=='4')&&(fillR<255)) {fillR++;fillG++;fillB++;}
  else if ((key=='5')&&(fillR>0)) {fillR--;fillG--;fillB--;}

  if ((key=='0')&&(key=='1')&&(key=='2')&&(key=='3')) {
    if (drawMode==2) {time=0; timeIncrease=true; timeInc = 25;}
    else if (drawMode==3) {time=0; timeIncrease=true; timeInc = 51;}
    else timeInc = 5;
  }
  
  if (moveLight) {
    if (((key=='w')||(key=='W'))&&(Light[selectedLight][POSITIONi][Yi]>0)) Light[selectedLight][POSITIONi][Yi]-=1;
    if (((key=='a')||(key=='A'))&&(Light[selectedLight][POSITIONi][Xi]>0)) Light[selectedLight][POSITIONi][Xi]-=1;
    if (((key=='s')||(key=='S'))&&(Light[selectedLight][POSITIONi][Yi]<height)) Light[selectedLight][POSITIONi][Yi]+=1;
    if (((key=='d')||(key=='D'))&&(Light[selectedLight][POSITIONi][Xi]<width)) Light[selectedLight][POSITIONi][Xi]+=1;
    if ((key=='q')||(key=='Q')) Light[selectedLight][POSITIONi][Zi]+=1;
    if ((key=='e')||(key=='E')) Light[selectedLight][POSITIONi][Zi]-=1;
  }
  else if ((key=='a')||(key=='A')) AMBIENTon[selectedLight]=!AMBIENTon[selectedLight];
  else if ((key=='d')||(key=='D')) DIFFUSEon[selectedLight]=!DIFFUSEon[selectedLight];
  else if ((key=='s')||(key=='S')) SPECULARon[selectedLight]=!SPECULARon[selectedLight];
  else if ((key=='r')||(key=='R')) selectedColor=0;
  else if ((key=='g')||(key=='G')) selectedColor=1;
  else if ((key=='b')||(key=='B')) selectedColor=2;
  else if ((key=='w')||(key=='W')) selectedColor=3;
  if ((key=='n')||(key=='N')) numDisplay=!numDisplay;
  if (((key=='m')||(key=='M'))&&(ActiveLights[selectedLight]==1)) moveLight = !moveLight;  
  else if ((key=='l')||(key=='L')) {
    if (ActiveLights[selectedLight]==1) {
      ActiveLights[selectedLight] = 0;
      numOfActiveLights--;
    }
    else {
      ActiveLights[selectedLight] = 1;
      numOfActiveLights++;
    }    
  }
  if (key=='+') {
    if (selectedTextArea==0) selectedObject = (selectedObject+1)%nSff;
    if (selectedTextArea==1) {
      projectionMode[selectedObject]=(projectionMode[selectedObject]+1)%2;
      DogaProjectionFX(projectionMode[selectedObject],near,far,top,bottom,left,right);
    }
    if (selectedTextArea==2) {
      rx[selectedObject]+=0.05;
      if (rx[selectedObject]>6.28) rx[selectedObject]-=6.28;
      ry[selectedObject]+=0.05;
      if (ry[selectedObject]>6.28) ry[selectedObject]-=6.28;
      rz[selectedObject]+=0.05;
      if (rz[selectedObject]>6.28) rz[selectedObject]-=6.28;
    }
    if (selectedTextArea==3) {
      rx[selectedObject]+=0.05;
      if (rx[selectedObject]>6.28) rx[selectedObject]-=6.28;
    }
    if (selectedTextArea==4) {
      ry[selectedObject]+=0.05;
      if (ry[selectedObject]>6.28) ry[selectedObject]-=6.28;
    }
    if (selectedTextArea==5) {
      rz[selectedObject]+=0.05;
      if (rz[selectedObject]>6.28) rz[selectedObject]-=6.28;
    }
    if (selectedTextArea==6) {
      sx[selectedObject]+=0.05;
      sy[selectedObject]+=0.05;
      sz[selectedObject]+=0.05;
    }
    if (selectedTextArea==7) {
      sx[selectedObject]+=0.05;
    }
    if (selectedTextArea==8) {
      sy[selectedObject]+=0.05;
    }
    if (selectedTextArea==9) {
      sz[selectedObject]+=0.05;
    }
    if (selectedTextArea==10) {
      tx[selectedObject]+=0.05;
      ty[selectedObject]+=0.05;
      tz[selectedObject]+=0.05;
    }
    if (selectedTextArea==11) {
      tx[selectedObject]+=0.05;
    }
    if (selectedTextArea==12) {
      ty[selectedObject]+=0.05;
    }
    if (selectedTextArea==13) {
      tz[selectedObject]+=0.05;
    }
    if ((selectedTextArea>0)&&(selectedTextArea<14)) ApplyMatrix(selectedObject);
    if (selectedTextArea==14){
      activeFile=(activeFile+1)%nFile;
      readInBasicFile();  
      size(xRes,yRes);
      selectedObject=0;
    }
    if (selectedTextArea==16) pM[0]+=0.01;
    if (selectedTextArea==17) pM[1]+=0.01;
    if (selectedTextArea==18) pM[2]+=0.01;
    if (selectedTextArea==19) uM[0]+=0.01;
    if (selectedTextArea==20) uM[1]+=0.01;
    if (selectedTextArea==21) uM[2]+=0.01;
    if (selectedTextArea==22) vM[0]+=0.01;
    if (selectedTextArea==23) vM[1]+=0.01;
    if (selectedTextArea==24) vM[2]+=0.01;
    if (selectedTextArea==25) nM[0]+=0.01;
    if (selectedTextArea==26) nM[1]+=0.01;
    if (selectedTextArea==27) nM[2]+=0.01;
    if ((selectedTextArea>14)&&(selectedTextArea<28)) {
      DogaCameraFX(pM,uM,vM,nM);
      for(i=0;i<nSff;i++) ApplyMatrix(i);
    }
    if (selectedTextArea==28) drawWireFrames=(drawWireFrames+1)%3;
    if (selectedTextArea==29) showLightSources=!showLightSources;

    if (selectedTextArea==fI+mI-5) drawMode = (drawMode+1)%4;
    if (selectedTextArea==fI+mI-4) selectedLight = (selectedLight+1)%numOfLights;
    if ((selectedTextArea==fI+mI-3)&&(Light[selectedLight][AMBIENTi][selectedColor]<255)) Light[selectedLight][AMBIENTi][selectedColor]+=3;
    if ((selectedTextArea==fI+mI-2)&&(Light[selectedLight][DIFFUSEi][selectedColor]<255)) Light[selectedLight][DIFFUSEi][selectedColor]+=3;
    if ((selectedTextArea==fI+mI-1)&&(Light[selectedLight][SPECULARi][selectedColor]<255)) Light[selectedLight][SPECULARi][selectedColor]+=3;
  }
  else if (key=='-') {
    if (selectedTextArea==0) selectedObject = (selectedObject-1)%nSff;
    if (selectedTextArea==1) {
      projectionMode[selectedObject]=(projectionMode[selectedObject]-1)%2;
      DogaProjectionFX(projectionMode[selectedObject],near,far,top,bottom,left,right);
    }
    if (selectedTextArea==2) {
      rx[selectedObject]-=0.05;
      if (rx[selectedObject]<0) rx[selectedObject]+=6.28;
      ry[selectedObject]-=0.05;
      if (ry[selectedObject]<0) ry[selectedObject]+=6.28;
      rz[selectedObject]-=0.05;
      if (rz[selectedObject]<0) rz[selectedObject]+=6.28;
    }
    if (selectedTextArea==3) {
      rx[selectedObject]-=0.05;
      if (rx[selectedObject]<0) rx[selectedObject]+=6.28;
    }
    if (selectedTextArea==4) {
      ry[selectedObject]-=0.05;
      if (ry[selectedObject]<0) ry[selectedObject]+=6.28;
    }
    if (selectedTextArea==5) {
      rz[selectedObject]-=0.05;
      if (rz[selectedObject]<0) rz[selectedObject]+=6.28;
    }
    if (selectedTextArea==6) {
      if (sx[selectedObject]>0.05) sx[selectedObject]-=0.05;
      if (sy[selectedObject]>0.05) sy[selectedObject]-=0.05;
      if (sz[selectedObject]>0.05) sz[selectedObject]-=0.05;
    }
    if (selectedTextArea==7) {
      if (sx[selectedObject]>0.05) sx[selectedObject]-=0.05;
    }
    if (selectedTextArea==8) {
      if (sy[selectedObject]>0.05) sy[selectedObject]-=0.05;
    }
    if (selectedTextArea==9) {
      if (sz[selectedObject]>0.05) sz[selectedObject]-=0.05;
    }
    if (selectedTextArea==10) {
      tx[selectedObject]-=0.05;
      ty[selectedObject]-=0.05;
      tz[selectedObject]-=0.05;
    }
    if (selectedTextArea==11) {
      tx[selectedObject]-=0.05;
    }
    if (selectedTextArea==12) {
      ty[selectedObject]-=0.05;
    }
    if (selectedTextArea==13) {
      tz[selectedObject]-=0.05;
    }
    if ((selectedTextArea>0)&&(selectedTextArea<14)) ApplyMatrix(selectedObject);
    if (selectedTextArea==16) pM[0]-=0.01;
    if (selectedTextArea==17) pM[1]-=0.01;
    if (selectedTextArea==18) pM[2]-=0.01;
    if (selectedTextArea==19) uM[0]-=0.01;
    if (selectedTextArea==20) uM[1]-=0.01;
    if (selectedTextArea==21) uM[2]-=0.01;
    if (selectedTextArea==22) vM[0]-=0.01;
    if (selectedTextArea==23) vM[1]-=0.01;
    if (selectedTextArea==24) vM[2]-=0.01;
    if (selectedTextArea==25) nM[0]-=0.01;
    if (selectedTextArea==26) nM[1]-=0.01;
    if (selectedTextArea==27) nM[2]-=0.01;
    if ((selectedTextArea>14)&&(selectedTextArea<28)) {
      DogaCameraFX(pM,uM,vM,nM);
      for(i=0;i<nSff;i++) ApplyMatrix(i);
    }
    if (selectedTextArea==28) drawWireFrames=(drawWireFrames+2)%3;
    if (selectedTextArea==29) showLightSources=!showLightSources;

    if (selectedTextArea==fI+mI-5) drawMode = (drawMode-1+4)%4;
    if (selectedTextArea==fI+mI-4) selectedLight = (selectedLight-1+numOfLights)%numOfLights;
    if ((selectedTextArea==fI+mI-3)&&(Light[selectedLight][AMBIENTi][selectedColor]>0)) Light[selectedLight][AMBIENTi][selectedColor]-=3;
    if ((selectedTextArea==fI+mI-2)&&(Light[selectedLight][DIFFUSEi][selectedColor]>0)) Light[selectedLight][DIFFUSEi][selectedColor]-=3;
    if ((selectedTextArea==fI+mI-1)&&(Light[selectedLight][SPECULARi][selectedColor]>0)) Light[selectedLight][SPECULARi][selectedColor]-=3;
  }
  endControl();
}
void mousePressed() {
  selectedTextArea=-1;
  if ((mouseX>textArea[0][0])&&(mouseY<=textArea[13][3])) selectedTextArea = (int)(mouseY-(mouseY%20))/20; //TEXTS ON THE RIGHT SIDE
  else if ((mouseX<=textArea[14][1])&&(mouseY<=textArea[29][3])) selectedTextArea = 14+(int)(mouseY-(mouseY%20))/20; //TEXTS ON THE LEFT UPPER SIDE
  else if (mouseY>=textArea[fI][2]) selectedTextArea = fI+(int)(mouseY-textArea[fI][2]-(mouseY%20))/20; // TEXT ON THE DOWN SIDE

  if (selectedTextArea==0) selectedObject = (selectedObject+1)%nSff;
  else if (selectedTextArea==1) {
    projectionMode[selectedObject]=(projectionMode[selectedObject]+1)%2;
    DogaProjectionFX(projectionMode[selectedObject],near,far,top,bottom,left,right);
    ApplyMatrix(selectedObject);
  }
  else if (selectedTextArea==14){
    activeFile=(activeFile+1)%nFile;
    readInBasicFile();  
    size(xRes,yRes);
    selectedObject=0;
  }
  //WIREFRAME DRAWING SETUP
  else if (selectedTextArea==28) {
    if (drawMode<3) drawWireFrames=(drawWireFrames+1)%3;
    else drawWireFrames=(drawWireFrames+1)%2;
  }
  else if (selectedTextArea==29) showLightSources=!showLightSources;  
  else if (selectedTextArea==fI+mI-5) {
    drawMode=(drawMode+1)%4;
    if (drawMode>1) {time=0; timeIncrease=true; timeInc = 51;}
    else timeInc = 5;
  }
  else if (selectedTextArea==fI+mI-4) {
    selectedLight=(selectedLight+1)%numOfLights;
    moveLight = false;
  }
  endControl();
}
void endControl() {
  if (drawMode!=3) warningText = new String("To see light-effects switch to lighting mode.[Click the text below or press '3']");
  else if (numOfActiveLights==0) warningText = new String("(To see light-effects you have to activate at least 1 light).");
  else if (ActiveLights[selectedLight]==1) {
    if (moveLight) warningText = new String("You are moving the light.Use w,a,s,d,q,e to move the light.Then click m.");
    else warningText = new String("Click on light type.Then press r,g,b,w then press '+ or -' to change the light values.");
  }
  else warningText = new String("You have another active light but not this one. To control it click on 'Light_'");

  if ((drawMode<3)&&(drawWireFrames==0)) drawWireFrames=1;
  else if ((drawMode==3)&&(drawWireFrames==2)) drawWireFrames=0;
}
